package xyz.lilei23.framework.transaction;



import com.sun.org.apache.bcel.internal.generic.IF_ACMPEQ;
import net.sf.cglib.proxy.MethodProxy;
import xyz.lilei23.framework.annotation.AutoWired;
import xyz.lilei23.framework.annotation.Transactional;
import xyz.lilei23.framework.aop.MethodInterceptor;
import xyz.lilei23.framework.utils.DynamicProxyAnnotationUtil;

import java.lang.reflect.Method;

/**
 * @author lilei
 * @date 31/07/2021 16:20
 * @version 1.0
 **/
public class TransactionMethodInterceptor implements MethodInterceptor {

    public TransactionManager transactionManager;

    private TransactionMethodInterceptor(TransactionManager transactionManager) {
        this.transactionManager = transactionManager;
    }

    public static TransactionMethodInterceptor getInstance(TransactionManager transactionManager){
        if (transactionManager==null){
            throw new RuntimeException("获取事务管理异常");
        }
        return new TransactionMethodInterceptor(transactionManager);
    }

    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        Object result;
        Transactional annotation = (Transactional) DynamicProxyAnnotationUtil.findAnnotationFromProxy(Transactional.class,o,method);
        // 如果没有注解直接放行
        if (annotation == null){
            return methodProxy.invokeSuper(o, args);
        }
        Class<? extends Exception>[] rollbackFor = annotation.rollbackFor();
        try{
            // 开启事务
            transactionManager.beginTransaction();
            result = methodProxy.invokeSuper(o, args);
            // 提交事务
            transactionManager.commit();
        }catch (Exception e) {
            e.printStackTrace();
            for (Class<? extends Exception> aClass : rollbackFor) {
                if (aClass.isAssignableFrom(e.getClass())) {
                    // 回滚事务
                    transactionManager.rollback();
                    throw e;
                }
            }
            throw e;
        }
        return result;
    }
}
